#include "TcpServer.hpp"
#include <memory>

using namespace tcpserver;

static void usage(std::string proc)
{
    std::cerr << "usage:\t\n"
              << proc << "port" << std::endl;
}

bool cal(const Request &req, Response &resp)
{
    // req已经有结构化数据了，可以直接使用
    resp.exitcode = OK;
    resp.result = OK;

    switch (req._op)
    {
    case '+':
        resp.result = req._x + req._y;
        break;
    case '-':
        resp.result = req._x - req._y;

        break;
    case '*':
        resp.result = req._x * req._y;

        break;
    case '/':
    {
        if (req._y == 0)
            resp.exitcode = DIV_ZERO;
        else
            resp.result = req._x / req._y;
    }
    break;
    case '%':
    {
        if (req._y == 0)
            resp.exitcode = MOD_ZERO;
        else
            resp.result = req._x + req._y;
    }
    break;
    default:
        resp.exitcode = OP_ERROR;
        break;
    }
}

void calculate(Connection *conn)
{
    std::string onePackage;
    while (ParseOnePackage(conn->_inbuffer, &onePackage))
    {
        std::string reqStr;
        if (!deLength(onePackage, &reqStr))
            return;
        std::cout << "去掉报头的正文：\n"
                  << reqStr << std::endl;

        // 2.对请求反序列化
        Request req;
        if (!req.deserialize(reqStr))
            return;

        Response resp;
        cal(req, resp);

        std::string respStr;
        resp.serialize(&respStr);

        // 5.然后再发送响应
        // 5.1构建成为一个完整的报文
        conn->_outbuffer += enLength(respStr);

        std::cout << "--------------------result: " << conn->_outbuffer << std::endl;
    }
    // 发回去,直接发
    if (conn->_sender)
        conn->_sender(conn);

    // 如果没有发送完毕，需要对对于的sock开启事件的关心，如果发完了，我们要关闭对写事件的关系！
    // if (!conn->_outbuffer.empty())
    //     conn->_tsp->EnableReadWrite(conn, true, true);
    // else
    //     conn->_tsp->EnableReadWrite(conn, true, false);
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);

    std::unique_ptr<TcpServer> tsvr(new TcpServer(calculate, port));
    tsvr->initServer();
    tsvr->Dispatch();

    return 0;
}

///////////////////////////////////简洁版reactor(半同步半异步IO)//////////////////////////////////////

// 正确处理的处理IO + 协议定制 + 业务逻辑 = Reactor  -> Linux网络中，最常用，最频繁的一种网络IO设计模式
// 基于ET模式下的Reactor，处理所有的IO

// 在epoll中能不能直接发送呢？？不能！！！
// 用户无法保证发送条件是就绪的！谁最清楚？？epoll
// 什么叫做写发送事件就绪？ 发送缓冲区有空间！
// 服务器刚启动，或者很多情况下， 发送事件一直都是就绪的！可以直接放松，只不过，如果我们没有发送完怎么办？
// 需要下一次发送，这里也要要求没一个sock有自己的发送缓冲区
// 有时候发送缓冲区没就绪：注定要将sock的EPOLLOUT事件也要有时候注册进epoll
// 一般读事件对应epoll我们要常设，写事件的关心，对于epoll，我们要按需设置！

// Reaction:反应堆，connection：原材料  ，事件派发：那个底层事件就绪好了，就去派发任务
// Reaction -> 即保证了就绪事件通知+负责IO(半同步)，还负责业务处理(半异步)